﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Drawing
{
    /// <summary>
    /// _ellipse 椭圆
    /// </summary>
    public class EllipseAction : ElementAction
    {
        public static LcCreateMethod[] CreateMethods;
        static EllipseAction()
        {
            CreateMethods = new LcCreateMethod[]
            {
                new LcCreateMethod
                {
                    Name = "CP",
                    Description = "指定中心点创建椭圆",
                    Steps = new LcCreateStep[]
                    {
                        new LcCreateStep { Name=  "Step0", Options= "指定椭圆中心点:" },
                        new LcCreateStep { Name=  "Step1", Options= "指定轴端点:" },
                        new LcCreateStep { Name=  "Step2", Options= "指定另一个半轴长度:" },
                    }
                },
                new LcCreateMethod
                {
                    Name = "AEP",
                    Description = "指定轴，端点创建椭圆",
                    Steps = new LcCreateStep[]
                    {
                        new LcCreateStep { Name=  "Step0", Options= "指定轴端点:" },
                        new LcCreateStep { Name=  "Step1", Options= "指定轴另一个端点:" },
                        new LcCreateStep { Name=  "Step2", Options= "指定另一个半轴长度:" },
                    }
                }
            };
        }

        internal static void Initilize()
        {
            ElementActions.Ellipse = new EllipseAction();
            LcDocument.ElementActions.Add(BuiltinElementType.Ellipse, ElementActions.Ellipse);
        }
        private EllipseAction() { } 
        public EllipseAction(DocumentRuntime docRt) : base(docRt)
        {
           

        }
        private LcCreateMethod _currMethod = null;
        private Vector2d? _p0;
        private Vector2d? _p1;
        private Vector2d? _p2;
        public async void ExecCreate(string[] args = null) 
        {
            PointInputer inputer = new PointInputer(this.docRt);
            this.StartCreating();
            _currMethod = CreateMethods.ToList().Find(m => m.Name == args[0]);
            if (_currMethod == null)
                goto End;
            if (_currMethod.Name == "CP")
                goto cp_step0;
            else if (_currMethod.Name == "AEP")
                goto aep_step0;

            cp_step0:
            var cp_result0 = await inputer.Execute(_currMethod.Steps[0].Options);
            if (inputer.isCancelled||cp_result0==null)
                goto EndByCancel;
            if (cp_result0.Value == null)
            {
                if (cp_result0.Option != null)
                {
                    inputer.WriteInfo("TODO..");
                }
                goto cp_step0;
            }
            else 
            {
                _p0 = (Vector2d)cp_result0.Value;
                goto cp_step1;
            }
            cp_step1:
            var cp_result1 = await inputer.Execute(_currMethod.Steps[0].Options);
            if (inputer.isCancelled || cp_result1 == null)
                goto EndByCancel;
            if (cp_result1.Value == null)
            {
                if (cp_result1.Option != null)
                {
                    inputer.WriteInfo("TODO..");
                }
                goto cp_step1;
            }
            else
            {
                _p1 = (Vector2d)cp_result1.Value;
                goto cp_step2;
            }
        cp_step2:
            var cp_result2 = await inputer.Execute(_currMethod.Steps[0].Options);
            if (inputer.isCancelled || cp_result2 == null)
                goto EndByCancel;
            if (cp_result2.Value == null)
            {
                if (cp_result2.Option != null)
                {
                    inputer.WriteInfo("TODO..");
                }
                goto cp_step2;
            }
            else
            {
                _p2 = (Vector2d)cp_result1.Value;
                goto End;
            }
        aep_step0:
            aep_step1:
            aep_step2:
            
            EndByCancel:
            this.Cancel();
            this.EndCreating();
        End:
            this.CreateEllipse();
            this.EndCreating();
        }
        private void CreateEllipse() 
        {
            if (_currMethod.Name == "CP") 
            {
                var p0p1 = (_p1 - _p0);
                var axisX = p0p1?.Normalized;
                docRt.Document.ModelSpace.AddEllipse(this._p0.Value, axisX.Value, p0p1.Value.Length, Vector2d.Distance(_p2.Value, _p0.Value));
            }
        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }
        public override void DrawAuxLines(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);

            if (_currMethod.Name == "CP")
            {
                if (_p0 == null) return;

                var movePoint = mp.ToSKPoint();
                var center = this.vportRt.ConvertWcsToScr(_p0.Value).ToSKPoint();
              
                //第二点
                if (_p1 == null)
                {
                    if (center == movePoint) return;
                    using (var pen = new SKPaint { Color = SKColors.Orange, IsStroke = true, PathEffect = Constants.SelectedEffect })
                    {
                        canvas.DrawLine(center, movePoint, pen);
                    }
                }
                //第三点
                else
                {
                    var p1= this.vportRt.ConvertWcsToScr(_p1.Value).ToSKPoint();
                    if (p1 == movePoint) return;
                    using (var pen = new SKPaint { Color = SKColors.Orange, IsStroke = true, PathEffect = Constants.SelectedEffect })
                    {
                        canvas.DrawLine(p1, movePoint, pen);

                    }
                    using (var pen = new SKPaint { Color = SKColors.White, IsStroke = true })
                    {
                        var cV2 = center.ToVector2d();
                        var p1V2 = p1.ToVector2d();
                        var cp1V2 = (p1V2 - cV2);
                        var mvV2 = movePoint.ToVector2d();
                        var cmV2 = (mvV2 - cV2);
                        var mAngle = cmV2.Angle() - cp1V2.Angle();
                        var mY = GeoUtils.PointDistanceToLine(mvV2, cV2, p1V2);
                        var radiusY = mY / Math.Sin(mAngle);
                        getEllipse(cV2, cp1V2.Normalized, cp1V2.Length, radiusY, out var rect, out var angle);
                        canvas.RotateRadians((float)angle, center.X,center.Y);
                        canvas.DrawOval(rect, pen);
                        canvas.RotateRadians(-(float)angle, center.X, center.Y);

                    }
                }
            }
           
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3d matrix)
        {
            var ellipse = element as LcEllipse;
            var mcenter = matrix.MultiplyPoint(ellipse.Center);
            var axisY = Vector2d.RotateInRadian(ellipse.AxisX, Utils.HalfPI);
            var mT = matrix.MultiplyPoint(ellipse.Center + axisY * ellipse.RadiusY);
            var mR = matrix.MultiplyPoint(ellipse.Center + ellipse.AxisX * ellipse.RadiusX );

            var scCenter = this.vportRt.ConvertWcsToScr(mcenter);
            var scMT = this.vportRt.ConvertWcsToScr(mT);
            var scMR = this.vportRt.ConvertWcsToScr(mR);
            var angle = (float)(scMR - scCenter).Angle();
            var hwidth = Vector2d.Distance(scCenter, scMR);
            var hheight = Vector2d.Distance(scCenter, scMT);
            var rect = new SKRect((float)(scCenter.X - hwidth), (float)(scCenter.Y + hheight), (float)(scCenter.X + hwidth),(float)( scCenter.Y + hheight));
            //get Layer color 
            bool isDragCopy = (matrix != Matrix3d.Zero);
            var pen = this.GetDrawPen(ellipse, isDragCopy);
            var skScCenter = scCenter.ToSKPoint();
            canvas.RotateRadians(angle, skScCenter.X, skScCenter.Y);
            canvas.DrawOval(rect,pen);
            canvas.RotateRadians(-angle, skScCenter.X, skScCenter.Y);
        }
        private void getEllipse(Vector2d center,Vector2d axisX,double radiusX,double radiusY,out SKRect rect,out double angle) 
        {
            angle = axisX.Angle();
            rect=new SKRect((float)(center.X-radiusX), (float)(center.Y+radiusY), (float)(center.X+radiusX), (float)(center.Y-radiusY));
        }
    }
}
